﻿using System;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;

namespace MolyMade.Moly.HttpRequest.DataTypes
{
    public class Response
    {
        public Response(Request request, HttpWebResponse httpWebResponse,TimeSpan elapsed)
        {
            this.Request = request;
            this._httpWebResponse = httpWebResponse;
            this.Elapsed = elapsed;
        }

        public HttpWebResponse _httpWebResponse;
        public TimeSpan Elapsed { get; }

        private string _text;
        private byte[] _content;
        private MemoryStream _raw;

        private HttpCookieCollection _cookies
        {
            get
            {
                HttpCookieCollection collection = new HttpCookieCollection();
                foreach (Cookie cookie in _httpWebResponse.Cookies)
                {
                    collection.Add(new HttpCookie(cookie.Name,cookie.Value));
                }
                foreach (Cookie cookie in Utilities.Utilities.StringToCookieCollection(_httpWebResponse.Headers["Set-Cookie"]))
                {
                    if(collection.AllKeys.Contains(cookie.Name)) continue;
                    else
                    {
                        collection.Add(new HttpCookie(cookie.Name,cookie.Value));
                    }
                }
                return collection;
            }
        }

        public HttpCookieCollection Cookies => _cookies;
        public string Url => _httpWebResponse.ResponseUri.ToString();
        public Uri Uri => _httpWebResponse.ResponseUri;
        public WebHeaderCollection Headers => _httpWebResponse.Headers;
        public byte[] Content => _content ?? (_content = this.Raw.ToArray());
        public string Text => _text ?? (_text = this.Encoding.GetString(this.Content));
        public int StatusCode => (int)_httpWebResponse.StatusCode;
        public string StatusDescription => _httpWebResponse.StatusDescription;
        public Request Request { get; }

        public Encoding Encoding
        {
            get
            {
                Encoding encoding;
                Match metaInfo = Regex.Match(Encoding.ASCII.GetString(this.Content), Statics.Statics.Enconding,
                    RegexOptions.IgnoreCase);
                string matchValue = metaInfo.Groups[1].Value.Trim().ToLower();
                var headerEncoding =
                    _httpWebResponse?.CharacterSet?.Trim()
                        .ToLower()
                        .Replace("\"", "")
                        .Replace("\'", "")
                        .Replace("iso-8859-1", "gbk");
                if (metaInfo.Success&&matchValue.Length>2)
                {
                    var bodyEncoding = metaInfo.Groups[1].Value.Trim()
                        .ToLower()
                        .Replace("\"", "")
                        .Replace("'", "")
                        .Replace(";", "")
                        .Replace("iso-8859-1", "gbk");
                    try
                    {
                        encoding = Encoding.GetEncoding(bodyEncoding);
                        return encoding;
                    }
                    catch 
                    {
                        encoding = !string.IsNullOrEmpty(headerEncoding) ? Encoding.GetEncoding(headerEncoding) : Encoding.UTF8;
                    }
                }
                else
                {
                    encoding = !string.IsNullOrEmpty(headerEncoding) ? Encoding.GetEncoding(headerEncoding) : Encoding.UTF8;
                }
                return encoding;
            }
        }

        public MemoryStream Raw
        {
            get
            {
                if (_raw == null)
                {
                    using (Stream stream = _httpWebResponse.GetResponseStream())
                    {
                        _raw = new MemoryStream();
                        if (_httpWebResponse.ContentEncoding.Equals("gzip",StringComparison.InvariantCultureIgnoreCase))
                        {
                            new GZipStream(stream,CompressionMode.Decompress).CopyTo(_raw);
                        }
                        else
                        {
                            stream.CopyTo(_raw);
                        }
                    }
                }
                return _raw;
            }
        }

        public void RaiseForStatus()
        {
            if (this._httpWebResponse.StatusCode != HttpStatusCode.OK)
            {
                throw new Exception(_httpWebResponse.StatusDescription);
            }
        }




    }
}
